package asynctask

import (
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/pkg/errors"
	"scase.io/application-auto-scaling-service/pkg/cloudresource"
	"scase.io/application-auto-scaling-service/pkg/common"
	"scase.io/application-auto-scaling-service/pkg/db"
	event "scase.io/application-auto-scaling-service/pkg/service/event"
	"scase.io/application-auto-scaling-service/pkg/utils/logger"
	"time"
)

// 删除命名空间异步任务
type DelPodNamespaceTask struct {
	groupId string
	BaseTask
	event *event.EventService
}

func NewDelPodNamespaceTask(groupId string) *DelPodNamespaceTask {
	return &DelPodNamespaceTask{
		groupId: groupId,
	}
}

// GetKey get id of the resource corresponding to the task
func (t *DelPodNamespaceTask) GetKey() string {
	return t.groupId
}

// GetType get task type
func (t *DelPodNamespaceTask) GetType() string {
	return db.TaskTypeDeleteNamespace
}

func (t *DelPodNamespaceTask) Run(log *logger.FMLogger) error {
	// 多次未删除完，不将伸缩组状态置deleted，直接结束任务
	if t.GetRetryTimes() >= common.AsyncMaxRetryTimes {
		log.Error("[delete_namespace] delete namespace [%s] fail after %d retry", t.groupId, common.AsyncMaxRetryTimes)
		return nil
	}
	// 1. 从数据库读取group，若没有，说明资源已删除完毕
	group, err := db.GetNotDeletedGroupById("", t.groupId)
	if err != nil {
		if errors.Is(err, orm.ErrNoRows) {
			log.Info("[delete_namespace] Namespace[%s] has been deleted, do nothing", group.FleetId)
			return db.TxRecordDeletePodNamespaceTaskComplete(group.Id)
		}
		return err
	}
	t.event, err = event.NewEventService(group.ProjectId, nil, log)
	if err != nil {
		log.Error("[delete_namespace]new event service error:%+v", err)
		return err
	}
	//// 2. 删除伸缩策略 和 对应的监控任务
	if db.GroupPolicyRelationTable().CheckRelationExist(group.Id, "") {
		if err = t.delPolicyAndMonitorTask(log, group.Id); err != nil {
			log.Error("[delete_namespace] delete policy and monitor task error:%+v", err)
			return err
		}
	}
	// 3. 修改Namespace状态为deleting，置成功相当于锁，最长等待时间为任务多次不成功，加上任务的运行间隔得到的大致最长时间
	// 如果超过最长等待次数，则强制置锁，只有扩容任务可能会长时间等待，如果任务最终完成了，会有游离的实例，考虑将此纳入事件审计中
	if err := t.WaitGroupDeleting(log, group); err != nil {
		log.Error("[delete_namespace] wait group [%s] delete with error:%+v", group.Id, err)
		return err
	}
	podCtrl, err := cloudresource.GetPodController(group.ProjectId)
	if err != nil {
		log.Error("[delete_namespace] get controller of group [%s] error:%+v", group.Id, err)
		return err
	}
	if err := podCtrl.DeleteNamespace(group.FleetId, group.Id, log); err != nil {
		log.Error("[delete_namespace] delete namespace [%s] error:%+v", group.Id, err)
		return err
	}
	if err := db.PodInfoTable().DeletePodInfoByGroupId(group.Id); err != nil {
		log.Error("[delete_namespace] delete pod_info in db error:%+v", err)
		return err
	}
	eveReq := t.event.BuildInstanceEventReq("[delete-namespace] success", group.Id, fmt.Sprintf("delete-namespace [%s] of fleet [%s] success", t.groupId, group.FleetId),
		fmt.Sprintf("delete-namespace [%s] of fleet [%s] success", t.groupId, group.FleetId), common.EventTraceStateNormal)
	t.event.RegisterEvent(eveReq, group.ProjectId, log)

	return db.TxRecordDeletePodNamespaceTaskComplete(group.Id)
}

// 删除伸缩策略 和 对应的监控任务
func (t *DelPodNamespaceTask) delPolicyAndMonitorTask(log *logger.FMLogger, groupId string) error {
	groupPolicyList, err := db.GroupPolicyRelationTable().GetRelation("", groupId, "", 0, 0)
	if err != nil {
		log.Error("[delete_namespace] get group-policy relation error:%+v", err)
		return err
	}
	// 删除任务，删除策略关联
	for _, relation := range groupPolicyList {
		monitorTask, err := db.GetMetricMonitorTaskByScalingPolicy(relation.ScalingPolicyId)
		if err != nil {
			if !errors.Is(err, orm.ErrNoRows) {
				log.Error("[delete_namespace] get policy error:%+v", err)
				return err
			}
		}
		if monitorTask != nil {
			if err := db.DeleteMetricMonitorTask(monitorTask.Id); err != nil {
				log.Error("[delete_namespace] delete monitor task [%s] error:%+v", monitorTask.Id, err)
				return err
			}
		}

		if err := db.GroupPolicyRelationTable().DeleteRelation(groupId, relation.ScalingPolicyId); err != nil {
			log.Error("[delete_namespace] delete group-policy relation error:%+v", err)
			return err
		}
	}
	log.Info("[delete_namespace] The scaling policies[%+v] of group[%s] has been deleted", groupPolicyList, t.groupId)
	return nil
}

func (t *DelPodNamespaceTask) WaitGroupDeleting(log *logger.FMLogger, group *db.ScalingGroup) error {
	for retry := 0; retry <= defaultMaxWaitTimes; retry++ {
		err := db.ChangeScalingGroupState2Deleting(log, t.groupId)
		if err != nil {
			// 当前Namespace状态不支持删除，重试
			if errors.Is(err, common.ErrScalingGroupCannotBeDeleted) {
				time.Sleep(waitGroupCanBeDeletedInternal)
				continue
			}
			return err
		}
		if retry >= defaultMaxWaitTimes {
			log.Warn("[delete_namespace] set group [%s] state to [deleting] fail after retry %d times", t.groupId, defaultMaxWaitTimes)
			err := db.UpdateScalingGroupState(t.groupId, db.ScalingGroupStateDeleting)
			if err != nil {
				log.Error("[delete_namespace] set group [%s] state to [deleting] fail with error:%+v", t.groupId, err)
				eveReq := t.event.BuildInstanceEventReq("[delete-group] failed", group.Id, fmt.Sprintf("delete group [%s] of fleet [%s] failed with error:%+v",
					t.groupId, group.FleetId, err.Error()),
					"delete scaling group failed", common.EventTraceStateIncident)
				t.event.RegisterEvent(eveReq, group.ProjectId, log)
				return err
			}
		}
		// 修改伸缩组的状态“deleting”成功，继续执行之后的操作
		break
	}
	return nil
}
